<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绘制折线</title>
    <script src="jquery-3.6.0.js"></script>
    <script src="svg.min.js"></script>
    <link rel="stylesheet" href="svg.select.js/svg.select.min.css"/>
    <script src="svg.draw.min.js"></script>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        body {
            padding: 10px;
        }
    </style>
</head>
<body>
<div id="svg-canvas" tabindex="-1"></div>
<script>
    SVG.extend(SVG.Element, {
        selectize2: function (selectGroup) {
            // selectGroup是用来存放选择框的g标签
            // 返回选择框的id，用于后续的处理
            // 1. 绘制选择框
            let bbox = this.bbox();
            let selRect = selectGroup.rect(bbox.w, bbox.h).move(bbox.x, bbox.y).addClass('svg_select_boundingRect');
            return selRect.node.id;
        }
    });
</script>
<script>
    // 绑定键盘事件
    let addSelect = false;
    $("#svg-canvas").keydown(function (e) {
        switch (e.which) {
            case 16:  // shift
            case 17:  // ctrl
                addSelect = true;  // 复选
                break;
            default:
                break
        }
    });

    $("#svg-canvas").keyup(function (e) {
        switch (e.which) {
            case 16:  // shift
            case 17:  // ctrl
                addSelect = false;  // 复选
                break;
            default:
                break
        }
    });

</script>
<script>
    let drawing = new SVG("svg-canvas").size(2000, 2000);
    let selectRect = [0, 0, 0, 0]
    let rect;
    let selectItemIDArr = []  // 框选的缓冲区，目前被框选的对象ID
    let selectedItem = {}  // key为选择对象的ID，value为选择框的ID

    let drawingGroup = drawing.group()  // 用于存在绘制的图形
    let selectGroup = drawing.group()  // 用于存选择标记
    let selectRectGroup = drawing.group()  // 用于存拖选框

    let rectSelectMode = false;  // 框选模式
    let dragMode = false;  // 拖动模式
    let normalSelectMode = true;  // 点选模式，默认为true

    drawingGroup.svg('<polyline id="test" points="444.666679918766,397.33334517478943,507,397.33334517478943,507,462,603,462,603,560" stroke="#000000" fill="none" style="stroke-width: 2;"></polyline>')
    drawingGroup.svg('<polyline id="test2" points="746.6666889190674,278.0000082850456,825,278.0000082850456,825,346,876,346,876,478" stroke="#000000" fill="none" style="stroke-width: 2;"></polyline>')

    // 点选参考这个函数
    // drawing.on('mousemove', function (event) {
    //     if (document.elementFromPoint(event.pageX, event.pageY).nodeName === 'polyline') {
    //         console.log(document.elementsFromPoint(event.pageX, event.pageY))
    //     }
    // })


    drawing.on('mousedown', function (event) {
        // 如果点击在了可选择的对象上
        //   1. 如果鼠标移动，进入拖动模式
        //   2. 如果鼠标不移动，进入选择模式
        // 否则进入框选模式

        // 判断是否点击在可选择的对象上
        //   1. 如果点击在上面，绑定鼠标移动事件，一旦移动进入拖动模式
        //   2. 如果没有点击在上面，进入框选模式
        let pointEle = document.elementsFromPoint(event.pageX, event.pageY)  // 在该点上面的所有元素
        let onSelectableItem = false;
        for (let ele of pointEle) {
            // 遍历判断是否有可选择的对象
            let eleSVG = ele.instance;
            // 找到最顶层的元素（drawingGroup的子元素）
            if (eleSVG && drawingGroup.has(eleSVG)) {  // ele存在instance的属性，并且ele.instance属于drawingGroup，则是个可选择的对象
                onSelectableItem = true;
            }
        }
        if (onSelectableItem) {
            // 如果点击在上面，绑定鼠标移动事件，一旦移动进入拖动模式
            drawing.on('mousemove', function () {
                // 添加进入拖动模式的代码
                dragMode = true;
                normalSelectMode = false;
            });
        } else {
            // 框选模式
            drawing.on('mousemove', function (emm) {
                // 框选模式
                // 1. 绘制拖选框（仅绘制一次）
                // 2. 判断图形是否在拖选框内，如果在里面就放入缓冲区，否则从缓冲区中删除
                if (!rectSelectMode) {  // 通过判断rectSelectMode来区分是否是第一次执行
                    rect = selectRectGroup.rect();
                    rect.draw(emm)
                        .attr("fill", "rgba(0,196,255,0.2)")
                        .attr("stroke", "rgb(0,196,255)")
                        .attr('stroke-width', 1)
                    selectRect[0] = emm.offsetX
                    selectRect[1] = emm.offsetY
                }
                rectSelectMode = true;
                normalSelectMode = false;
                boundingJudge(emm);
            })
        }
    })

    drawing.on('mouseup', function (event) {
        if (rectSelectMode) {
            // 框选模式
            // 删除拖选框
            // 将缓冲区内的元素写入selectedItem
            // 添加选中标记
            // 回到普通选择模式
            rect.draw('cancel');
            drawingGroup.each(function (i, e) {
                if (selectItemIDArr.includes(this.node.id)) {
                    if (selectedItem.hasOwnProperty(this.node.id)) {
                        // 如果选中的已经包含了这个id，什么都不用做
                    } else {
                        // 将选择框的ID和选中对象关联起来
                        selectedItem[this.node.id] = this.selectize2(selectGroup)
                    }
                } else {
                    // 当不处于复选模式的时候，没有选中的对象，如果在selectedItem当中，
                    // 需要删除选择框，并从selectedItem中删掉
                    if (!addSelect) {
                        if (selectedItem.hasOwnProperty(this.node.id)) {
                            let selID = selectedItem[this.node.id];
                            SVG.get(selID).remove();
                            delete selectedItem[this.node.id];
                        }
                    }
                }
            })
            rectSelectMode = false;
            normalSelectMode = true;
        } else if (dragMode) {
            dragMode = false;
            normalSelectMode = true;
        } else if (normalSelectMode) {
            let pointEle = document.elementsFromPoint(event.pageX, event.pageY)  // 在该点上面的所有元素

            if (!addSelect) {
                // 非复选的状态
                // 1. 取消选择所有元素
                //   根据ID找到选择框，删除掉
                // 2. 给选中的元素增加选择框，把信息添加到selectedItem中
                for (let id in selectedItem) {
                    let selRectID = selectedItem[id]
                    SVG.get(selRectID).remove()
                    delete selectedItem[id]
                }
                for (let ele of pointEle) {
                    let eleSVG = ele.instance;
                    // 找到最顶层的元素（drawingGroup的子元素）
                    if (eleSVG && drawingGroup.has(eleSVG)) {  // ele存在instance的属性，并且ele.instance属于drawingGroup
                        // 这里需要加入位置重合元素的判断
                        // 添加到已经选择的元素
                        selectedItem[ele.id] = eleSVG.selectize2(selectGroup);
                        break;  // 为了防止同时选择了多个，这里要跳出循环
                    }
                }
            } else {
                // 复选状态
                // 1. 判断元素是否已经被选中，如果选中不进行任何操作
                // 2. 给选中的元素增加选择框，把信息添加到selectedItem中
                for (let ele of pointEle) {
                    let eleSVG = ele.instance;
                    // 找到最顶层的元素（drawingGroup的子元素）
                    if (eleSVG && drawingGroup.has(eleSVG)) {  // ele存在instance的属性，并且ele.instance属于drawingGroup
                        // 这里需要加入位置重合元素的判断
                        // 添加到已经选择的元素
                        if (ele.id in selectedItem) {  // 判断元素是否已经被选中，如果选中不进行任何操作
                            continue;  // 用continue而不是break可以选择到重合的元素
                        }
                        // 元素此前未选中，给选中的元素增加选择框，把信息添加到selectedItem中
                        selectedItem[ele.id] = eleSVG.selectize2(selectGroup);
                        break;  // 为了防止同时选择了多个，这里要跳出循环
                    }
                }
            }

        }
        drawing.off('mousemove');
    })

    // let ele = SVG.get("test")
    // console.log(ele.bbox())

    // 获取所有svg元素的bbox
    // 将所有svg元素的bbox x1,y1,x2,y2 坐标保存起来，形式为
    // {id:[x1,y1,x2,y2],id:[],...}
    let bboxIDDict = {}
    drawingGroup.each(function (i, child) {
        bboxIDDict[this.node.id] = [this.bbox().x, this.bbox().y, this.bbox().x2, this.bbox().y2]
    })

    function boundingJudge(emm) {
        // 在鼠标移动的过程中判断是否选中某个对象
        selectRect[2] = emm.offsetX
        selectRect[3] = emm.offsetY
        let xLittle = selectRect[0] > selectRect[2] ? selectRect[2] : selectRect[0]
        let xLarge = selectRect[0] < selectRect[2] ? selectRect[2] : selectRect[0]
        let yLittle = selectRect[1] > selectRect[3] ? selectRect[3] : selectRect[1]
        let yLarge = selectRect[1] < selectRect[3] ? selectRect[3] : selectRect[1]
        for (let id in bboxIDDict) {
            let x1 = bboxIDDict[id][0]
            let y1 = bboxIDDict[id][1]
            let x2 = bboxIDDict[id][2]
            let y2 = bboxIDDict[id][3]
            // 如果元素在框内，将元素的id添加到selectItemIDArr，否则从selectItemIDArr中删除
            if (xLittle < x1 && yLittle < y1 && xLarge > x2 && yLarge > y2) {
                if (!selectItemIDArr.includes(id)) {
                    selectItemIDArr.push(id)
                }
            } else if (selectItemIDArr.includes(id)) {
                let newArray = [];
                for (let item of selectItemIDArr) {
                    if (item !== id) {
                        newArray.push(item)
                    }
                }
                selectItemIDArr = newArray
            }
        }

    }

</script>
</body>
</html>